home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 February: Tool Chest / Dev.CD Feb 99 TC.toast / Tool Chest / Interapplication Communication / ScriptableStuffItEngine / Project / MoreFiles / FSpCompat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-02  |  25.3 KB  |  928 lines  |  [TEXT/CWIE]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    FSSpec compatibility functions.
  5. **
  6. **    by Jim Luther, Apple Developer Technical Support Emeritus
  7. **
  8. **    File:        FSpCompat.c
  9. **
  10. **    Copyright © 1992-1998 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  17. **    after having made changes. If you're going to re-distribute the source,
  18. **    we require that you make it clear in the source that the code was
  19. **    descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. /*
  23. **    If building application 68K code, set GENERATENODATA to 0 for faster code.
  24. **    If building stand-alone 68K code, set GENERATENODATA to 1 so globals
  25. **        (static variables) are not used.
  26. */
  27. #ifndef GENERATENODATA
  28. #define GENERATENODATA 0
  29. #endif
  30.  
  31. #include <Types.h>
  32. #include <Errors.h>
  33. #include <LowMem.h>
  34. #include <Gestalt.h>
  35. #include <Resources.h>
  36. #include <Script.h>
  37.  
  38. #define    __COMPILINGMOREFILES
  39.  
  40. #include "MoreFilesExtras.h"
  41. #include "FSpCompat.h"
  42.  
  43. /*****************************************************************************/
  44.  
  45. /* local constants */
  46.  
  47. enum {
  48.     gestaltBugFixAttrsTwo                    = 'bugy',
  49.     gestaltFSpExchangeFilesCompatibilityFix    = 26,
  50.     gestaltBugFixAttrsThree                    = 'bugx',
  51.     gestaltFSpCreateScriptSupportFix        = 1
  52. };
  53.  
  54. /*****************************************************************************/
  55.  
  56. /* static prototypes */
  57.  
  58.  
  59. #if !__MACOSSEVENORLATER
  60. static    Boolean    FSHasFSSpecCalls(void);
  61.  
  62. static    Boolean    QTHasFSSpecCalls(void);
  63. #endif    /* !__MACOSSEVENORLATER */
  64.  
  65. #if !__MACOSSEVENFIVEORLATER
  66. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void);
  67.  
  68. static    OSErr    GenerateUniqueName(short volume,
  69.                                    long *startSeed,
  70.                                    long dir1,
  71.                                    long dir2,
  72.                                    StringPtr uniqueName);
  73. #endif    /* !__MACOSSEVENFIVEORLATER */
  74.  
  75. #if !__MACOSSEVENFIVEONEORLATER
  76. static    Boolean    HasFSpCreateScriptSupportFix(void);
  77. #endif    /* !__MACOSSEVENFIVEONEORLATER */
  78.  
  79. /*****************************************************************************/
  80.  
  81. /* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
  82.  
  83. #if !__MACOSSEVENORLATER
  84. static    Boolean    FSHasFSSpecCalls(void)
  85. {
  86.     long            response;
  87. #if !GENERATENODATA
  88.     static Boolean    tested = false;
  89.     static Boolean    result = false;
  90. #else
  91.     Boolean    result = false;
  92. #endif
  93.     
  94. #if !GENERATENODATA
  95.     if ( !tested )
  96.     {
  97.         tested = true;
  98. #endif
  99.         if ( Gestalt(gestaltFSAttr, &response) == noErr )
  100.         {
  101.             result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
  102.         }
  103. #if !GENERATENODATA
  104.     }
  105. #endif
  106.     return ( result );
  107. }
  108. #endif    /* !__MACOSSEVENORLATER */
  109.  
  110. /*****************************************************************************/
  111.  
  112. /* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
  113. /* except for FSpExchangeFiles. */
  114.  
  115. #if !__MACOSSEVENORLATER
  116. static    Boolean    QTHasFSSpecCalls(void)
  117. {
  118.     long            response;
  119. #if !GENERATENODATA
  120.     static Boolean    tested = false;
  121.     static Boolean    result = false;
  122. #else
  123.     Boolean    result = false;
  124. #endif
  125.     
  126. #if !GENERATENODATA
  127.     if ( !tested )
  128.     {
  129.         tested = true;
  130. #endif
  131.         result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
  132. #if !GENERATENODATA
  133.     }
  134. #endif
  135.     return ( result );
  136. }
  137. #endif    /* !__MACOSSEVENORLATER */
  138.  
  139. /*****************************************************************************/
  140.  
  141. /* HasFSpExchangeFilesCompatibilityFix returns true if FSpExchangeFiles */
  142. /* compatibility code has been fixed in system software. */
  143. /* This was fixed by System Update 3.0, so if SystemSevenFiveOrLater */
  144. /* is true, then we know the fix is in. */
  145.  
  146. #if !__MACOSSEVENFIVEORLATER
  147. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void)
  148. {
  149.     long            response;
  150. #if !GENERATENODATA
  151.     static Boolean    tested = false;
  152.     static Boolean    result = false;
  153. #else    /* !GENERATENODATA */
  154.     Boolean    result = false;
  155. #endif    /* !GENERATENODATA */
  156.     
  157. #if !GENERATENODATA
  158.     if ( !tested )
  159.     {
  160.         tested = true;
  161. #endif    /* !GENERATENODATA */
  162.         if ( Gestalt(gestaltBugFixAttrsTwo, &response) == noErr )
  163.         {
  164.             result = ((response & (1L << gestaltFSpExchangeFilesCompatibilityFix)) != 0);
  165.         }
  166. #if !GENERATENODATA
  167.     }
  168. #endif    /* !GENERATENODATA */
  169.     return ( result );
  170. }
  171. #endif    /* !__MACOSSEVENFIVEORLATER */
  172.  
  173. /*****************************************************************************/
  174.  
  175. /* HasFSpCreateScriptSupportFix returns true if FSpCreate and */
  176. /* FSpCreateResFile have been fixed in system software to correctly set */
  177. /* the scriptCode in the volume's catalog. */
  178. /* This was fixed by System 7.5 Update 1.0 */
  179.  
  180. #if !__MACOSSEVENFIVEONEORLATER
  181. static    Boolean    HasFSpCreateScriptSupportFix(void)
  182. {
  183.     long            response;
  184. #if !GENERATENODATA
  185.     static Boolean    tested = false;
  186.     static Boolean    result = false;
  187. #else
  188.     Boolean    result = false;
  189. #endif    /* !GENERATENODATA */
  190.     
  191. #if !GENERATENODATA
  192.     if ( !tested )
  193.     {
  194.         tested = true;
  195. #endif    /* !GENERATENODATA */
  196.         if ( Gestalt(gestaltBugFixAttrsThree, &response) == noErr )
  197.         {
  198.             result = ((response & (1L << gestaltFSpCreateScriptSupportFix)) != 0);
  199.         }
  200. #if !GENERATENODATA
  201.     }
  202. #endif    /* !GENERATENODATA */
  203.     return ( result );
  204. }
  205. #endif    /* !__MACOSSEVENFIVEONEORLATER */
  206.  
  207. /*****************************************************************************/
  208.  
  209. /*
  210. **    File Manager FSp calls
  211. */
  212.  
  213. /*****************************************************************************/
  214.  
  215. pascal    OSErr    FSMakeFSSpecCompat(short vRefNum,
  216.                                    long dirID,
  217.                                    ConstStr255Param fileName,
  218.                                    FSSpec *spec)
  219. {
  220.     OSErr    result;
  221.     
  222. #if !__MACOSSEVENORLATER
  223.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  224.     {
  225.         Boolean    isDirectory;
  226.         
  227.         result = GetObjectLocation(vRefNum, dirID, fileName,
  228.                                     &(spec->vRefNum), &(spec->parID), spec->name,
  229.                                     &isDirectory);
  230.     }
  231. #endif    /* !__MACOSSEVENORLATER */
  232.     {
  233.         /* Let the file system create the FSSpec if it can since it does the job */
  234.         /* much more efficiently than I can. */
  235.         result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
  236.  
  237.         /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
  238.         /* returned in the parID field when making an FSSpec to the volume's */
  239.         /* root directory by passing a full pathname in MakeFSSpec's */
  240.         /* fileName parameter. Fixed in Mac OS 8.1 */
  241.         if ( (result == noErr) && (spec->parID == 0) )
  242.             spec->parID = fsRtParID;
  243.     }
  244.     return ( result );
  245. }
  246.  
  247. /*****************************************************************************/
  248.  
  249. pascal    OSErr    FSpOpenDFCompat(const FSSpec *spec,
  250.                                 char permission,
  251.                                 short *refNum)
  252. {
  253. #if !__MACOSSEVENORLATER
  254.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  255.     {
  256.         OSErr            result;
  257.         HParamBlockRec    pb;
  258.         
  259.         pb.ioParam.ioVRefNum = spec->vRefNum;
  260.         pb.fileParam.ioDirID = spec->parID;
  261.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  262.         pb.ioParam.ioVersNum = 0;
  263.         pb.ioParam.ioPermssn = permission;
  264.         pb.ioParam.ioMisc = NULL;
  265.         result = PBHOpenSync(&pb);    /* OpenDF not supported by System 6, so use Open */
  266.         *refNum = pb.ioParam.ioRefNum;
  267.         return ( result );
  268.     }
  269.     else
  270. #endif    /* !__MACOSSEVENORLATER */
  271.     {
  272.         return ( FSpOpenDF(spec, permission, refNum) );
  273.     }
  274. }
  275.  
  276. /*****************************************************************************/
  277.  
  278. pascal    OSErr    FSpOpenRFCompat(const FSSpec *spec,
  279.                                 char permission,
  280.                                 short *refNum)
  281. {
  282. #if !__MACOSSEVENORLATER
  283.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  284.     {
  285.         OSErr            result;
  286.         HParamBlockRec    pb;
  287.         
  288.         pb.ioParam.ioVRefNum = spec->vRefNum;
  289.         pb.fileParam.ioDirID = spec->parID;
  290.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  291.         pb.ioParam.ioVersNum = 0;
  292.         pb.ioParam.ioPermssn = permission;
  293.         pb.ioParam.ioMisc = NULL;
  294.         result = PBHOpenRFSync(&pb);
  295.         *refNum = pb.ioParam.ioRefNum;
  296.         return ( result );
  297.     }
  298.     else
  299. #endif    /* !__MACOSSEVENORLATER */
  300.     {
  301.         return ( FSpOpenRF(spec, permission, refNum) );
  302.     }
  303. }
  304.  
  305. /*****************************************************************************/
  306.  
  307. pascal    OSErr    FSpCreateCompat(const FSSpec *spec,
  308.                                 OSType creator,
  309.                                 OSType fileType,
  310.                                 ScriptCode scriptTag)
  311. {
  312. #if !__MACOSSEVENFIVEONEORLATER
  313.     OSErr            result;
  314.     UniversalFMPB    pb;
  315.  
  316.     
  317.     if (
  318. #if !__MACOSSEVENORLATER
  319.          !FSHasFSSpecCalls() && !QTHasFSSpecCalls() &&
  320. #endif    /* !__MACOSSEVENORLATER */
  321.          !HasFSpCreateScriptSupportFix() )
  322.     {
  323.         /*    If FSpCreate isn't called, this code will be executed */
  324.         pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  325.         pb.hPB.fileParam.ioDirID = spec->parID;
  326.         pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  327.         pb.hPB.fileParam.ioFVersNum = 0;
  328.         result = PBHCreateSync(&(pb.hPB));
  329.         if ( result == noErr )
  330.         {
  331.             /* get info on created item */
  332.             pb.ciPB.hFileInfo.ioFDirIndex = 0;
  333.             result = PBGetCatInfoSync(&(pb.ciPB));
  334.             if ( result == noErr )
  335.             {
  336.                 /* Set fdScript in FXInfo */
  337.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  338.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  339.                 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  340.                 pb.ciPB.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  341.                                                             ((char)scriptTag | (char)0x80) :
  342.                                                             (smRoman);
  343.                 /* Set creator/fileType */
  344.                 pb.ciPB.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  345.                 pb.ciPB.hFileInfo.ioFlFndrInfo.fdType = fileType;
  346.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  347.                 pb.ciPB.hFileInfo.ioDirID = spec->parID;
  348.                 result = PBSetCatInfoSync(&(pb.ciPB));
  349.             }
  350.         }
  351.         return ( result );
  352.     }
  353.     else
  354. #endif    /* !__MACOSSEVENFIVEONEORLATER */
  355.     {
  356.         return ( FSpCreate(spec, creator, fileType, scriptTag) );
  357.     }
  358. }
  359.  
  360. /*****************************************************************************/
  361.  
  362. pascal    OSErr    FSpDirCreateCompat(const FSSpec *spec,
  363.                                    ScriptCode scriptTag,
  364.                                    long *createdDirID)
  365. {
  366. #if !__MACOSSEVENORLATER
  367.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  368.     {
  369.         OSErr            result;
  370.         UniversalFMPB    pb;
  371.         
  372.         pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  373.         pb.hPB.fileParam.ioDirID = spec->parID;
  374.         pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  375.         result = PBDirCreateSync(&(pb.hPB));
  376.         *createdDirID = pb.hPB.fileParam.ioDirID;
  377.         if ( result == noErr )
  378.         {
  379.             /* get info on created item */
  380.             pb.ciPB.dirInfo.ioFDirIndex = 0;
  381.             pb.ciPB.dirInfo.ioDrDirID = spec->parID;
  382.             result = PBGetCatInfoSync(&(pb.ciPB));
  383.             if ( result == noErr )
  384.             {
  385.                 /* Set frScript in DXInfo */
  386.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  387.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  388.                 /* (smRoman is 0). frScript is valid if high bit is set (see IM-6, page 9-38) */
  389.                 pb.ciPB.dirInfo.ioDrFndrInfo.frScript = (scriptTag >= smRoman) ?
  390.                                                             ((char)scriptTag | (char)0x80) :
  391.                                                             (smRoman);
  392.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  393.                 pb.ciPB.dirInfo.ioDrDirID = spec->parID;            
  394.                 result = PBSetCatInfoSync(&(pb.ciPB));
  395.             }
  396.         }
  397.         return ( result );
  398.     }
  399.     else
  400. #endif    /* !__MACOSSEVENORLATER */
  401.     {
  402.         return ( FSpDirCreate(spec, scriptTag, createdDirID) );
  403.     }
  404. }
  405.  
  406. /*****************************************************************************/
  407.  
  408. pascal    OSErr    FSpDeleteCompat(const FSSpec *spec)
  409. {
  410. #if !__MACOSSEVENORLATER
  411.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  412.     {
  413.         HParamBlockRec    pb;
  414.         
  415.         pb.ioParam.ioVRefNum = spec->vRefNum;
  416.         pb.fileParam.ioDirID = spec->parID;
  417.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  418.         pb.ioParam.ioVersNum = 0;
  419.         return ( PBHDeleteSync(&pb) );
  420.     }
  421.     else
  422. #endif    /* !__MACOSSEVENORLATER */
  423.     {
  424.         return ( FSpDelete(spec) );
  425.     }
  426. }
  427.  
  428. /*****************************************************************************/
  429.  
  430. pascal    OSErr    FSpGetFInfoCompat(const FSSpec *spec,
  431.                                   FInfo *fndrInfo)
  432. {
  433. #if !__MACOSSEVENORLATER
  434.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  435.     {
  436.         OSErr            result;
  437.         HParamBlockRec    pb;
  438.         
  439.         pb.fileParam.ioVRefNum = spec->vRefNum;
  440.         pb.fileParam.ioDirID = spec->parID;
  441.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  442.         pb.fileParam.ioFVersNum = 0;
  443.         pb.fileParam.ioFDirIndex = 0;
  444.         result = PBHGetFInfoSync(&pb);
  445.         *fndrInfo = pb.fileParam.ioFlFndrInfo;
  446.         return ( result );
  447.     }
  448.     else
  449. #endif    /* !__MACOSSEVENORLATER */
  450.     {
  451.         return ( FSpGetFInfo(spec, fndrInfo) );
  452.     }
  453. }
  454.  
  455. /*****************************************************************************/
  456.  
  457. pascal    OSErr    FSpSetFInfoCompat(const FSSpec *spec,
  458.                                   const FInfo *fndrInfo)
  459. {
  460. #if !__MACOSSEVENORLATER
  461.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  462.     {
  463.         OSErr            result;
  464.         HParamBlockRec    pb;
  465.         
  466.         pb.fileParam.ioVRefNum = spec->vRefNum;
  467.         pb.fileParam.ioDirID = spec->parID;
  468.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  469.         pb.fileParam.ioFVersNum = 0;
  470.         pb.fileParam.ioFDirIndex = 0;
  471.         result = PBHGetFInfoSync(&pb);
  472.         if ( result == noErr )
  473.         {
  474.             pb.fileParam.ioFlFndrInfo = *fndrInfo;
  475.             pb.fileParam.ioDirID = spec->parID;
  476.             result = PBHSetFInfoSync(&pb);
  477.         }
  478.         return ( result );
  479.     }
  480.     else
  481. #endif    /* !__MACOSSEVENORLATER */
  482.     {
  483.         return ( FSpSetFInfo(spec, fndrInfo) );
  484.     }
  485. }
  486.  
  487. /*****************************************************************************/
  488.  
  489. pascal    OSErr    FSpSetFLockCompat(const FSSpec *spec)
  490. {
  491. #if !__MACOSSEVENORLATER
  492.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  493.     {
  494.         HParamBlockRec    pb;
  495.         
  496.         pb.fileParam.ioVRefNum = spec->vRefNum;
  497.         pb.fileParam.ioDirID = spec->parID;
  498.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  499.         pb.fileParam.ioFVersNum = 0;
  500.         return ( PBHSetFLockSync(&pb) );
  501.     }
  502.     else
  503. #endif    /* !__MACOSSEVENORLATER */
  504.     {
  505.         return ( FSpSetFLock(spec) );
  506.     }
  507. }
  508.  
  509. /*****************************************************************************/
  510.  
  511. pascal    OSErr    FSpRstFLockCompat(const FSSpec *spec)
  512. {
  513. #if !__MACOSSEVENORLATER
  514.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  515.     {
  516.         HParamBlockRec    pb;
  517.         
  518.         pb.fileParam.ioVRefNum = spec->vRefNum;
  519.         pb.fileParam.ioDirID = spec->parID;
  520.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  521.         pb.fileParam.ioFVersNum = 0;
  522.         return ( PBHRstFLockSync(&pb) );
  523.     }
  524.     else
  525. #endif    /* !__MACOSSEVENORLATER */
  526.     {
  527.         return ( FSpRstFLock(spec) );
  528.     }
  529. }
  530.  
  531. /*****************************************************************************/
  532.  
  533. pascal    OSErr    FSpRenameCompat(const FSSpec *spec,
  534.                                 ConstStr255Param newName)
  535. {
  536. #if !__MACOSSEVENORLATER
  537.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  538.     {
  539.         HParamBlockRec    pb;
  540.         
  541.         pb.ioParam.ioVRefNum = spec->vRefNum;
  542.         pb.fileParam.ioDirID = spec->parID;
  543.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  544.         pb.ioParam.ioVersNum = 0;
  545.         pb.ioParam.ioMisc = (Ptr) newName;
  546.         return ( PBHRenameSync(&pb) );
  547.     }
  548.     else
  549. #endif    /* !__MACOSSEVENORLATER */
  550.     {
  551.         return ( FSpRename(spec, newName) );
  552.     }
  553. }
  554.  
  555. /*****************************************************************************/
  556.  
  557. pascal    OSErr    FSpCatMoveCompat(const FSSpec *source,
  558.                                  const FSSpec *dest)
  559. {
  560. #if !__MACOSSEVENORLATER
  561.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  562.     {
  563.         CMovePBRec    pb;
  564.         
  565.         /* source and destination volume must be the same */
  566.         if ( source->vRefNum != dest->vRefNum )
  567.             return ( paramErr );
  568.         
  569.         pb.ioNamePtr = (StringPtr) &(source->name);
  570.         pb.ioVRefNum = source->vRefNum;
  571.         pb.ioDirID = source->parID;
  572.         pb.ioNewDirID = dest->parID;
  573.         pb.ioNewName = (StringPtr) &(dest->name);
  574.         return ( PBCatMoveSync(&pb) );
  575.     }
  576.     else
  577. #endif    /* !__MACOSSEVENORLATER */
  578.     {
  579.         return ( FSpCatMove(source, dest) );
  580.     }
  581. }
  582.  
  583. /*****************************************************************************/
  584.  
  585. /* GenerateUniqueName generates a name that is unique in both dir1 and dir2 */
  586. /* on the specified volume. Ripped off from Feldman's code. */
  587.  
  588. #if !__MACOSSEVENFIVEORLATER
  589. static    OSErr    GenerateUniqueName(short volume,
  590.                                    long *startSeed,
  591.                                    long dir1,
  592.                                    long dir2,
  593.                                    StringPtr uniqueName)
  594. {
  595.     OSErr            error = noErr;
  596.     long            i;
  597.     CInfoPBRec        cinfo;
  598.     unsigned char    hexStr[16];
  599.     
  600.     for ( i = 0; i < 16; ++i )
  601.     {
  602.         if ( i < 10 )
  603.         {
  604.             hexStr[i] = 0x30 + i;
  605.         }
  606.         else
  607.         {
  608.             hexStr[i] = 0x37 + i;
  609.         }
  610.     }
  611.     
  612.     cinfo.hFileInfo.ioVRefNum = volume;
  613.     cinfo.hFileInfo.ioFDirIndex = 0;
  614.     cinfo.hFileInfo.ioNamePtr = uniqueName;
  615.  
  616.     while ( error != fnfErr )
  617.     {
  618.         (*startSeed)++;        
  619.         cinfo.hFileInfo.ioNamePtr[0] = 8;
  620.         for ( i = 1; i <= 8; i++ )
  621.         {
  622.             cinfo.hFileInfo.ioNamePtr[i] = hexStr[((*startSeed >> ((8-i)*4)) & 0xf)];
  623.         }
  624.         cinfo.hFileInfo.ioDirID = dir1;
  625.         error = fnfErr;
  626.         for ( i = 1; i <= 2; i++ )
  627.         {
  628.             error = error & PBGetCatInfoSync(&cinfo);
  629.             cinfo.hFileInfo.ioDirID = dir2;
  630.             if ( (error != fnfErr) && (error != noErr) )
  631.             {
  632.                 return ( error );
  633.             }
  634.         }
  635.     }
  636.     return ( noErr );
  637. }
  638. #endif    /* !__MACOSSEVENFIVEORLATER */
  639.  
  640. /*****************************************************************************/
  641.  
  642. pascal    OSErr    FSpExchangeFilesCompat(const FSSpec *source,
  643.                                        const FSSpec *dest)
  644. {
  645. #if !__MACOSSEVENFIVEORLATER
  646.     if ( 
  647. #if !__MACOSSEVENORLATER
  648.          !FSHasFSSpecCalls() &&
  649. #endif    /* !__MACOSSEVENORLATER */
  650.          !HasFSpExchangeFilesCompatibilityFix() )
  651.     {
  652.         HParamBlockRec            pb;
  653.         CInfoPBRec                catInfoSource, catInfoDest;
  654.         OSErr                    result, result2;
  655.         Str31                    unique1, unique2;
  656.         StringPtr                unique1Ptr, unique2Ptr, swapola;
  657.         GetVolParmsInfoBuffer    volInfo;
  658.         long                    theSeed, temp;
  659.         
  660.         /* Make sure the source and destination are on the same volume */
  661.         if ( source->vRefNum != dest->vRefNum )
  662.         {
  663.             result = diffVolErr;
  664.             goto errorExit3;
  665.         }
  666.         
  667.         /* Try PBExchangeFiles first since it preserves the file ID reference */
  668.         pb.fidParam.ioNamePtr = (StringPtr) &(source->name);
  669.         pb.fidParam.ioVRefNum = source->vRefNum;
  670.         pb.fidParam.ioDestNamePtr = (StringPtr) &(dest->name);
  671.         pb.fidParam.ioDestDirID = dest->parID;
  672.         pb.fidParam.ioSrcDirID = source->parID;
  673.     
  674.         result = PBExchangeFilesSync(&pb);
  675.     
  676.         /* Note: The compatibility case won't work for files with *Btree control blocks. */
  677.         /* Right now the only *Btree files are created by the system. */
  678.         if ( result != noErr )
  679.         {
  680.             pb.ioParam.ioNamePtr = NULL;
  681.             pb.ioParam.ioBuffer = (Ptr) &volInfo;
  682.             pb.ioParam.ioReqCount = sizeof(volInfo);
  683.             result2 = PBHGetVolParmsSync(&pb);
  684.             
  685.             /* continue if volume has no fileID support (or no GetVolParms support) */
  686.             if ( (result2 == noErr) && hasFileIDs(volInfo) )
  687.             {
  688.                 goto errorExit3;
  689.             }
  690.     
  691.             /* Get the catalog information for each file */
  692.             /* and make sure both files are *really* files */
  693.             catInfoSource.hFileInfo.ioVRefNum = source->vRefNum;
  694.             catInfoSource.hFileInfo.ioFDirIndex = 0;
  695.             catInfoSource.hFileInfo.ioNamePtr = (StringPtr) &(source->name);
  696.             catInfoSource.hFileInfo.ioDirID = source->parID;
  697.             catInfoSource.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
  698.             result = PBGetCatInfoSync(&catInfoSource);
  699.             if ( result != noErr )
  700.             {
  701.                 goto errorExit3;
  702.             }
  703.             if ( (catInfoSource.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  704.             {
  705.                 result = notAFileErr;
  706.                 goto errorExit3;
  707.             }
  708.             
  709.             catInfoDest.hFileInfo.ioVRefNum = dest->vRefNum;
  710.             catInfoDest.hFileInfo.ioFDirIndex = 0;
  711.             catInfoDest.hFileInfo.ioNamePtr = (StringPtr) &(dest->name);
  712.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  713.             catInfoDest.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
  714.             result = PBGetCatInfoSync(&catInfoDest);
  715.             if ( result != noErr )
  716.             {
  717.                 goto errorExit3;
  718.             }
  719.             if ( (catInfoDest.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  720.             {
  721.                 result = notAFileErr;
  722.                 goto errorExit3;
  723.             }
  724.             
  725.             /* generate 2 filenames that are unique in both directories */
  726.             theSeed = 0x64666A6C;    /* a fine unlikely filename */
  727.             unique1Ptr = (StringPtr)&unique1;
  728.             unique2Ptr = (StringPtr)&unique2;
  729.             
  730.             result = GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique1Ptr);
  731.             if ( result != noErr )
  732.             {
  733.                 goto errorExit3;
  734.             }
  735.     
  736.             GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique2Ptr);
  737.             if ( result != noErr )
  738.             {
  739.                 goto errorExit3;
  740.             }
  741.     
  742.             /* rename source to unique1 */
  743.             pb.fileParam.ioNamePtr = (StringPtr) &(source->name);
  744.             pb.ioParam.ioMisc = (Ptr) unique1Ptr;
  745.             pb.ioParam.ioVersNum = 0;
  746.             result = PBHRenameSync(&pb);
  747.             if ( result != noErr )
  748.             {
  749.                 goto errorExit3;
  750.             }
  751.             
  752.             /* rename dest to unique2 */
  753.             pb.ioParam.ioMisc = (Ptr) unique2Ptr;
  754.             pb.ioParam.ioVersNum = 0;
  755.             pb.fileParam.ioNamePtr = (StringPtr) &(dest->name);
  756.             pb.fileParam.ioDirID = dest->parID;
  757.             result = PBHRenameSync(&pb);
  758.             if ( result != noErr )
  759.             {
  760.                 goto errorExit2;    /* back out gracefully by renaming unique1 back to source */
  761.             }
  762.                 
  763.             /* If files are not in same directory, swap their locations */
  764.             if ( source->parID != dest->parID )
  765.             {
  766.                 /* move source file to dest directory */
  767.                 pb.copyParam.ioNamePtr = unique1Ptr;
  768.                 pb.copyParam.ioNewName = NULL;
  769.                 pb.copyParam.ioNewDirID = dest->parID;
  770.                 pb.copyParam.ioDirID = source->parID;
  771.                 result = PBCatMoveSync((CMovePBPtr) &pb);
  772.                 if ( result != noErr )
  773.                 {
  774.                     goto errorExit1;    /* back out gracefully by renaming both files to original names */
  775.                 }
  776.                 
  777.                 /* move dest file to source directory */
  778.                 pb.copyParam.ioNamePtr = unique2Ptr;
  779.                 pb.copyParam.ioNewDirID = source->parID;
  780.                 pb.copyParam.ioDirID = dest->parID;
  781.                 result = PBCatMoveSync((CMovePBPtr) &pb);
  782.                 if ( result != noErr)
  783.                 {
  784.                     /* life is very bad.  We'll at least try to move source back */
  785.                     pb.copyParam.ioNamePtr = unique1Ptr;
  786.                     pb.copyParam.ioNewName = NULL;
  787.                     pb.copyParam.ioNewDirID = source->parID;
  788.                     pb.copyParam.ioDirID = dest->parID;
  789.                     (void) PBCatMoveSync((CMovePBPtr) &pb);    /* ignore errors */
  790.                     goto errorExit1;    /* back out gracefully by renaming both files to original names */
  791.                 }
  792.             }
  793.             
  794.             /* Make unique1Ptr point to file in source->parID */
  795.             /* and unique2Ptr point to file in dest->parID */
  796.             /* This lets us fall through to the rename code below */
  797.             swapola = unique1Ptr;
  798.             unique1Ptr = unique2Ptr;
  799.             unique2Ptr = swapola;
  800.     
  801.             /* At this point, the files are in their new locations (if they were moved) */
  802.             /* Source is named Unique1 (name pointed to by unique2Ptr) and is in dest->parID */
  803.             /* Dest is named Unique2 (name pointed to by unique1Ptr) and is in source->parID */
  804.             /* Need to swap attributes except mod date and swap names */
  805.     
  806.             /* swap the catalog info by re-aiming the CInfoPB's */
  807.             catInfoSource.hFileInfo.ioNamePtr = unique1Ptr;
  808.             catInfoDest.hFileInfo.ioNamePtr = unique2Ptr;
  809.             
  810.             catInfoSource.hFileInfo.ioDirID = source->parID;
  811.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  812.             
  813.             /* Swap the original mod dates with each file */
  814.             temp = catInfoSource.hFileInfo.ioFlMdDat;
  815.             catInfoSource.hFileInfo.ioFlMdDat = catInfoDest.hFileInfo.ioFlMdDat;
  816.             catInfoDest.hFileInfo.ioFlMdDat = temp;
  817.             
  818.             /* Here's the swap (ignore errors) */
  819.             (void) PBSetCatInfoSync(&catInfoSource); 
  820.             (void) PBSetCatInfoSync(&catInfoDest);
  821.             
  822.             /* rename unique2 back to dest */
  823. errorExit1:
  824.             pb.ioParam.ioMisc = (Ptr) &(dest->name);
  825.             pb.ioParam.ioVersNum = 0;
  826.             pb.fileParam.ioNamePtr = unique2Ptr;
  827.             pb.fileParam.ioDirID = dest->parID;
  828.             (void) PBHRenameSync(&pb);    /* ignore errors */
  829.     
  830.             /* rename unique1 back to source */
  831. errorExit2:
  832.             pb.ioParam.ioMisc = (Ptr) &(source->name);
  833.             pb.ioParam.ioVersNum = 0;
  834.             pb.fileParam.ioNamePtr = unique1Ptr;
  835.             pb.fileParam.ioDirID = source->parID;
  836.             (void) PBHRenameSync(&pb); /* ignore errors */
  837.         }
  838. errorExit3: { /* null statement */ }
  839.         return ( result );
  840.     }
  841.     else
  842. #endif    /* !__MACOSSEVENFIVEORLATER */
  843.     {
  844.         return ( FSpExchangeFiles(source, dest) );
  845.     }
  846. }
  847.  
  848. /*****************************************************************************/
  849.  
  850. /* 
  851. **    Resource Manager FSp calls
  852. */
  853.  
  854. /*****************************************************************************/
  855.  
  856. pascal    short    FSpOpenResFileCompat(const FSSpec *spec,
  857.                                      SignedByte permission)
  858. {
  859. #if !__MACOSSEVENORLATER
  860.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  861.     {
  862.         return ( HOpenResFile(spec->vRefNum, spec->parID, spec->name, permission) );
  863.     }
  864.     else
  865. #endif    /* !__MACOSSEVENORLATER */
  866.     {
  867.         return ( FSpOpenResFile(spec, permission) );
  868.     }
  869. }
  870.  
  871. /*****************************************************************************/
  872.  
  873. pascal    void    FSpCreateResFileCompat(const FSSpec *spec,
  874.                                        OSType creator,
  875.                                        OSType fileType,
  876.                                        ScriptCode scriptTag)
  877. {    
  878. #if !__MACOSSEVENFIVEONEORLATER
  879.     if (
  880. #if !__MACOSSEVENORLATER
  881.          !FSHasFSSpecCalls() && !QTHasFSSpecCalls() &&
  882. #endif    /* !__MACOSSEVENORLATER */
  883.          !HasFSpCreateScriptSupportFix() )
  884.     {
  885.         OSErr            result;
  886.         CInfoPBRec        pb;
  887.         
  888.         HCreateResFile(spec->vRefNum, spec->parID, spec->name);
  889.         if ( ResError() == noErr )
  890.         {
  891.             /* get info on created item */
  892.             pb.hFileInfo.ioVRefNum = spec->vRefNum;
  893.             pb.hFileInfo.ioDirID = spec->parID;
  894.             pb.hFileInfo.ioNamePtr = (StringPtr) &(spec->name);
  895.             pb.hFileInfo.ioFDirIndex = 0;
  896.             result = PBGetCatInfoSync(&pb);
  897.             if ( result == noErr )
  898.             {
  899.                 /* Set fdScript in FXInfo */
  900.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  901.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  902.                 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  903.                 pb.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  904.                                                         ((char)scriptTag | (char)0x80) :
  905.                                                         (smRoman);
  906.                 /* Set creator/fileType */
  907.                 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  908.                 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
  909.                 
  910.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  911.                 pb.hFileInfo.ioDirID = spec->parID;
  912.                 result = PBSetCatInfoSync(&pb);
  913.             }
  914.             /* Set ResErr low memory global to result */
  915.             LMSetResErr(result);
  916.         }
  917.         return;
  918.     }
  919.     else
  920. #endif    /* !__MACOSSEVENFIVEONEORLATER */
  921.     {
  922.         FSpCreateResFile(spec, creator, fileType, scriptTag);
  923.         return;
  924.     }
  925. }
  926.  
  927. /*****************************************************************************/
  928.